home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Game-Power
/
Amiga Game-Power.iso
/
anwendungen
/
gw print
/
fragit
/
fragit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-20
|
16KB
|
529 lines
/* Fragit.c -- A simple memory thrasher/debugging tool.
*
* Copyright 1988 by Justin V. McCormick.
* May be freely used, modified, and distributed in any for for either
* commercial or personal profit or non-profit, so long as this notice
* remains prominently attached to the source code.
*
* In any case, the author makes no specific performance claims
* for this code and has no plans to maintain or support this code.
* Additionally, the author bears no liability or responsibility if the
* use of this code causes loss of data or sleep. This is your final
* notice -- you've been warned!
*/
/* Includes */
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/libraries.h>
#include <exec/interrupts.h>
#include <exec/semaphores.h>
#include <graphics/gfx.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <graphics/clip.h>
#include <graphics/text.h>
#include <libraries/dos.h>
#include <devices/timer.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <ctype.h>
/* External Functions */
extern struct Library *OpenLibrary();
extern VOID CloseLibrary();
extern struct Window *OpenWindow();
extern VOID CloseWindow();
extern struct Node *RemHead();
extern struct Node *RemTail();
extern struct Message *GetMsg();
extern VOID ReplyMsg();
extern BYTE *AllocMem();
extern VOID AddHead();
extern VOID FreeMem();
extern LONG AvailMem();
extern LONG *DateStamp();
extern LONG RangeRand();
extern LONG atol();
/* External Variables */
extern WORD Enable_Abort;
/* Local Definitions */
/* Local Structure Definitions */
struct FragNode /* For dynamic list of memory blocks */
{
struct MinNode fn_Node; /* Exec node linkage */
ULONG fn_Size; /* Size of allocated block */
BYTE *fn_Data; /* Pointer to allocated block */
};
/* Local Functions */
WORD main();
VOID ThrashMem();
LONG AddRandomFrag();
LONG FreeRandomFrag();
struct MinList *AllocMinList();
VOID FreeMinList();
struct FragNode *AllocFragNode();
VOID PrintMemoryStats();
VOID FreeFragNode();
VOID FreeAllFragNodes();
VOID ShowUsage();
VOID CleanUp();
VOID RattleDice();
WORD GetIDCMPEvents();
/* Global Variables */
struct GfxBase *GfxBase = 0L;
struct IntuitionBase *IntuitionBase = 0L;
struct MinList *FragList = 0L;
struct Window *FragWin = 0L;
UBYTE FragWinTitle[] = "Fragit 1.0 \xa9 1988 Justin V. McCormick";
struct NewWindow NewWin =
{
0,0,400,64,(UBYTE)0,(UBYTE)1,(ULONG)CLOSEWINDOW|RAWKEY,
(ULONG)WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SMART_REFRESH|NOCAREREFRESH,
0L,0L,FragWinTitle,0L,0L,0,0,0,0,(UWORD)WBENCHSCREEN
};
LONG AllocCount; /* Number of FragNodes in list */
LONG FailCount; /* Number of allocs that failed */
LONG TotalFragBytes; /* Number of bytes due to fn_Data frags */
WORD Verbose; /* Verbose output flag */
/* -------------------------------------------------------------------- */
/* Program entry point. */
/* -------------------------------------------------------------------- */
WORD main(argc, argv)
WORD argc;
BYTE **argv;
{
BYTE tstr[80];
WORD argindex;
register LONG minmem, minfrag, maxfrag;
/* Disable ^C processing */
Enable_Abort = 0;
/* Open libraries */
if ( (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == 0L)
CleanUp("No GfxBase?");
if ( (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == 0L)
CleanUp("No IntuitionBase?");
/* Set defaults, parse CLI arguments */
minmem = 100000L;
maxfrag = 10000L;
minfrag = 8L;
Verbose = 0;
argindex = 1;
if (argc > argindex)
{
if (argv[argindex][0] == '-' && (WORD)_tolower(argv[argindex][1]) == (WORD)'v')
{
Verbose = 1;
argindex++;
}
if (argc > argindex)
{
if (isdigit(argv[argindex][0]) == 0)
ShowUsage();
minmem = atol(argv[argindex]);
if (minmem <= 0L || minmem > 16000000L)
{
sprintf(tstr, "Minimum memory level '%ld' out of range.", minmem);
CleanUp(tstr);
}
argindex++;
if (argc > argindex)
{
if (isdigit(argv[argindex][0]) == 0)
ShowUsage();
minfrag = atol(argv[argindex]);
if (minfrag <= 0L || minfrag > 16000000L)
{
sprintf(tstr, "Minimum fragment size '%ld' out of range.", minfrag);
CleanUp(tstr);
}
argindex++;
if (argc > argindex)
{
if (isdigit(argv[argindex][0]) == 0)
ShowUsage();
maxfrag = atol(argv[argindex]);
if (maxfrag <= 0L || maxfrag > 16000000L)
{
sprintf(tstr, "Maximum fragment size '%ld' out of range.", maxfrag);
CleanUp(tstr);
}
if (maxfrag < minfrag)
{
sprintf(tstr, "Maximum fragment size '%ld' less than Minumum size '%ld'!", maxfrag, minfrag);
CleanUp(tstr);
}
}
}
}
}
/* Init RangeRand() seed */
RattleDice();
/* Open control window */
if ( (FragWin = OpenWindow(&NewWin)) == 0L)
CleanUp("Can't open window!");
/* Feedback the post-parsed args, and give them time to read it */
if (Verbose)
printf("MinMemLevel: %ld MinFragSize: %ld MaxFragSize: %ld\n", minmem, minfrag, maxfrag);
Delay(50L);
/* Perform thrash function using "minmem" as the lowest number of bytes that
* we will allow before freeing a memory fragment, and using "maxfrag" as
* the largest sized memory fragment to be randomly allocated
*/
ThrashMem(minmem, minfrag, maxfrag);
/* All done, free everything */
CleanUp("Done.");
}
/* -------------------------------------------------------------------- */
/* Play with random sized memory chunks, where: */
/* minfrag <= random size <= maxfrag */
/* -------------------------------------------------------------------- */
VOID ThrashMem(minmem, minfrag, maxfrag)
register LONG minmem, minfrag, maxfrag;
{
register WORD done;
/* Allocate and initialize MinList of FragNode fragments */
if ( (FragList = AllocMinList()) == 0L)
{
printf("No RAM for MinList structure?");
CleanUp();
}
/* Init variables, start thrash loop */
done = 0;
FailCount = AllocCount = TotalFragBytes = 0L;
while (!done)
{
/* Update ram statistics in TitleBar */
PrintMemoryStats();
/* If available ram is greater than "minmem", attempt to allocate a random
* sized fragment and add it to the MinList. Otherwise, free an entry
* picked at random from the linked-list of FragNodes.
*/
if (AvailMem((LONG)MEMF_PUBLIC) < minmem)
{
(VOID)FreeRandomFrag(FragList);
}
else
{
(VOID)AddRandomFrag(FragList, minfrag, maxfrag);
}
/* Check for exit conditions */
done = GetIDCMPEvents(FragWin->UserPort);
/* Crudely give other tasks a chance to run */
Delay(1L);
}
}
/* -------------------------------------------------------------------- */
/* Show current fragmentation and memory statistics in FragWin window */
/* -------------------------------------------------------------------- */
VOID PrintMemoryStats()
{
BYTE tstr[80];
static BYTE fmtstr1[] = "Frags: %4ld Fails: %4ld Allocated: %7ld";
static BYTE fmtstr2[] = "Type Available Largest";
static BYTE fmtstr3[] = "chip %7ld %7ld";
static BYTE fmtstr4[] = "fast %7ld %7ld";
static BYTE fmtstr5[] = "total %7ld %7ld";
LONG chipavail, chiplargest;
LONG fastavail, fastlargest;
LONG totalavail, abslargest;
register struct RastPort *rp;
Forbid();
chipavail = AvailMem(MEMF_CHIP);
chiplargest = AvailMem(MEMF_CHIP|MEMF_LARGEST);
fastavail = AvailMem(MEMF_FAST);
fastlargest = AvailMem(MEMF_FAST|MEMF_LARGEST);
Permit();
totalavail = chipavail + fastavail;
if (chiplargest > fastlargest)
abslargest = chiplargest;
else
abslargest = fastlargest;
sprintf(tstr, fmtstr1, AllocCount, FailCount, TotalFragBytes);
rp = FragWin->RPort;
SetAPen(rp, 1L);
Move(rp, 24L, 20L);
Text(rp, tstr, (LONG)strlen(tstr));
SetAPen(rp, 3L);
Move(rp, 90L, 30L);
Text(rp, fmtstr2, (LONG)strlen(fmtstr2));
SetAPen(rp, 1L);
sprintf(tstr, fmtstr3, chipavail, chiplargest);
Move(rp, 90L, 40L);
Text(rp, tstr, (LONG)strlen(tstr));
sprintf(tstr, fmtstr4, fastavail, fastlargest);
Move(rp, 90L, 50L);
Text(rp, tstr, (LONG)strlen(tstr));
sprintf(tstr, fmtstr5, totalavail, abslargest);
Move(rp, 90L, 60L);
Text(rp, tstr, (LONG)strlen(tstr));
}
/* -------------------------------------------------------------------- */
/* Given pointer to MinList and a maximum fragment size, allocate a */
/* FragNode with a fragment size minfrag <= size <= maxfrag and insert */
/* it at the head of the FragNode list. Return actual size of fragment. */
/* -------------------------------------------------------------------- */
LONG AddRandomFrag(list, minfrag, maxfrag)
struct MinList *list;
LONG minfrag, maxfrag;
{
register struct FragNode *tnode;
register LONG tsize;
if (minfrag == maxfrag)
tsize = minfrag;
else
tsize = RangeRand(maxfrag - minfrag) + minfrag;
tnode = AllocFragNode(tsize); /* alloc a random sized node */
tsize += (LONG)sizeof(struct FragNode); /* account for struct size! */
if (tnode != 0L)
{
AddHead(list, tnode);
if (Verbose)
printf("Adding a %7ld byte frag SUCCEEDED\n", tsize);
AllocCount++;
TotalFragBytes += tsize;
return(tsize);
}
else
{
if (Verbose)
printf("Adding a %7ld byte frag FAILED!\n", tsize);
FailCount++;
return(0L);
}
}
/* -------------------------------------------------------------------- */
/* Given a pointer to a MinList of FragNodes, remove one FragNode */
/* at random from the list, deallocate it, and return the fragment */
/* size that was deallocated. Return NULL (0L) if the list is empty. */
/* -------------------------------------------------------------------- */
LONG FreeRandomFrag(list)
struct MinList *list;
{
register LONG i, j;
register struct FragNode *tnode;
/* Empty list! just return NULL */
if (list->mlh_TailPred == list)
return(0L);
/* Generate a random number N, such that 0L <= N <= 99L */
j = RangeRand(100L);
/* Search through the MinList N times, restarting at lh_Head if we
* hit the end of the list before finding the Nth node.
*/
tnode = (struct FragNode *)list->mlh_Head;
for (i = 0L; i < j; i++)
{
tnode = (struct FragNode *)tnode->fn_Node.mln_Succ;
if (tnode == 0L)
tnode = (struct FragNode *)list->mlh_Head;
}
/* Remove this node from the list, grab it's size and deallocate */
Remove(tnode);
i = tnode->fn_Size + (LONG)sizeof(struct FragNode);
if (Verbose)
printf("Freeing %7ld byte frag (0x%08lx)\n", i, tnode->fn_Data);
FreeFragNode(tnode);
AllocCount--;
TotalFragBytes -= i;
/* Return the actual size of fragment deallocated */
return(i);
}
/* -------------------------------------------------------------------- */
/* Given a IntuiMsgPort, process IDCMP messages received. If we get */
/* a RAWKEY == RETURN, RAWKEY == ESCAPE, or CLOSEWINDOW event, return */
/* TRUE (1). Else, return FALSE (0).
/* -------------------------------------------------------------------- */
WORD GetIDCMPEvents(userport)
register struct IntuiMessage *userport;
{
register struct IntuiMessage *imsg;
register ULONG class;
register UWORD code;
register UWORD qualifier;
register WORD retval;
retval = 0;
while ( (imsg = (struct IntuiMessage *)GetMsg(userport)) != 0L)
{
class = imsg->Class;
code = imsg->Code;
qualifier = imsg->Qualifier;
ReplyMsg(imsg);
switch (class)
{
case RAWKEY:
if (code == 0xc4 || code == 0xc5)
retval = 1;
break;
case CLOSEWINDOW:
retval = 1;
break;
}
}
return (retval);
}
/* -------------------------------------------------------------------- */
/* Allocate and initialize a MinList structure, return pointer to same. */
/* -------------------------------------------------------------------- */
struct MinList *AllocMinList()
{
register struct MinList *mlist;
mlist = (struct MinList *)AllocMem((LONG)sizeof(struct MinList), MEMF_PUBLIC);
if (mlist)
NewList(mlist);
return(mlist);
}
/* -------------------------------------------------------------------- */
/* Free memory allocated to a MinList structure, if allocated. */
/* -------------------------------------------------------------------- */
VOID FreeMinList(list)
struct MinList *list;
{
if (list)
FreeMem(list, (LONG)sizeof(struct MinList));
}
/* -------------------------------------------------------------------- */
/* Allocate and initialize a FragNode structure, return pointer or 0L */
/* -------------------------------------------------------------------- */
struct FragNode *AllocFragNode(datasize)
LONG datasize;
{
register struct FragNode *mnode;
mnode = (struct FragNode *)AllocMem(datasize + (LONG)sizeof(struct FragNode), MEMF_PUBLIC);
if (mnode != 0L)
{
mnode->fn_Size = datasize;
mnode->fn_Data = (BYTE *)((LONG)mnode + (LONG)sizeof(struct FragNode));
}
return(mnode);
}
/* -------------------------------------------------------------------- */
/* Free memory allocated to a FragNode structure, if allocated. */
/* -------------------------------------------------------------------- */
VOID FreeFragNode(mnode)
struct FragNode *mnode;
{
if (mnode)
FreeMem(mnode, (LONG)sizeof(struct FragNode) + mnode->fn_Size);
}
/* -------------------------------------------------------------------- */
/* Walk list of allocated FragNodes in a MinList and free each one, */
/* then deallocate the MinList itself. */
/* -------------------------------------------------------------------- */
VOID FreeAllFragNodes(list)
struct List *list;
{
register struct FragNode *tnode;
if (list)
{
while ( (tnode = (struct FragNode *)RemHead(list)) != 0L)
FreeFragNode(tnode);
FreeMinList(list);
}
}
/* -------------------------------------------------------------------- */
/* If CLI, print usage and exit. If Workbench, exit cleanly. */
/* -------------------------------------------------------------------- */
VOID ShowUsage()
{
CleanUp(\
"Version 1.0 - Dynamic memory thrasher.\n\
Copyright \xa9 1988 by Justin V. McCormick - Freely Redistributable\n\n\
\x9b1;33;40mUsage:\x9b0m Fragit [-verbose] [MinMemLevel] [MinFragSize] [MaxFragSize]\n\
Default Parameters: (100000) (12) (10000)\n" );
}
/* -------------------------------------------------------------------- */
/* Universal exit point for entire program. */
/* -------------------------------------------------------------------- */
VOID CleanUp(exitmsg)
BYTE *exitmsg;
{
if (exitmsg && Output() != 0L)
printf("\x9b1;33;40mFragit:\x9b0m %s\n", exitmsg);
FreeAllFragNodes(FragList);
if (FragWin)
CloseWindow(FragWin);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (GfxBase)
CloseLibrary(GfxBase);
exit(0);
}
/* -------------------------------------------------------------------- */
/* Attempt to make RangeRand() a little less predictable between runs. */
/* -------------------------------------------------------------------- */
VOID RattleDice()
{
struct DateStamp stime;
register WORD i, j;
register LONG seedval;
DateStamp(&stime);
seedval = stime.ds_Tick;
j = (WORD)RangeRand(seedval + 0xaa) & 0xff;
for (i = 0; i < j; i++)
(VOID)RangeRand(seedval);
}